package com.jwork.progress.config.aop;


import com.jwork.progress.params.CommonResponse;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.time.Duration;

@Aspect
@Component
public class SubmitTokenAspect {
    private static final Logger log = LoggerFactory.getLogger(SubmitTokenAspect.class);
    // 锁等待时间
    private static final Long LOCK_REDIS_WAIT_TIME = 3L;
    // 锁前缀
    private static final String LOCK_KEY_PRE = "SUBMIT:TOKEN:LOCK";
    // 默认锁对应的值
    private static final String DEFAULT_LOCK_VALUE = "DEFAULT_LOCK_VALUE";

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RedisLockService redisLockService;

    // 方法调用环绕拦截
    @Around(value = "@annotation(com.jwork.progress.config.annotation.SubmitToken)")
    public Object doAround(ProceedingJoinPoint joinPoint) {
        HttpServletRequest request = getHttpServletRequest();
        if (ObjectUtils.isEmpty(request)) return CommonResponse.fail("请求参数不能为空");
        String submitToken = request.getHeader("submitToken");
        if (ObjectUtils.isEmpty(submitToken)) return CommonResponse.fail("submitToken 不能为空");

        // 校验submitToken
        String submitTokenValue = stringRedisTemplate.opsForValue().get(submitToken);
        if (ObjectUtils.isEmpty(submitTokenValue)) return CommonResponse.fail("redis查无数据");

        // 尝试加锁
        String lockKey = LOCK_KEY_PRE + submitToken;
        boolean lock = redisLockService.tryLock(lockKey, DEFAULT_LOCK_VALUE, Duration.ofSeconds(LOCK_REDIS_WAIT_TIME));
        if (!lock) return CommonResponse.fail("锁没加上，服务正在处理，请勿重复提交！");

        try {
            log.info("触发调用...");
            log.error("错误记录...");
            // 后续流程
            Object result = joinPoint.proceed();
            //任务执行成功，清除submitToken缓存
            stringRedisTemplate.delete(submitToken);
            return result;
        } catch (Throwable e) {
            return CommonResponse.fail("业务处理异常！");
        } finally {
            // 手动释放锁
            redisLockService.releaseLock(lockKey, DEFAULT_LOCK_VALUE);
        }
    }

    /**
     * 获取请求对象
     *
     * @return
     */
    private HttpServletRequest getHttpServletRequest() {
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        HttpServletRequest request = sra.getRequest();
        return request;
    }
}
